package task1;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SinCos {
	
	private static final Logger LOGGER = Logger.getLogger(SinCos.class.getName());
	
	public double evaluate(int numberOfThreads, int range, double step){
		
		double result = 0;
		
		ExecutorService pull = Executors.newFixedThreadPool(numberOfThreads);
		
		int rangeForThread = (2 * range) / numberOfThreads;
		
		for(int i = 0; i < numberOfThreads; i++){
			
			double from = i * rangeForThread - range;
			double to = from + rangeForThread;
			if(i == numberOfThreads - 1){
				to = range + step;
			}
			
			try {
				result += pull.submit(new SinCosEvaluator(from, to, step)).get();
			} catch (InterruptedException e) {
				LOGGER.log(Level.SEVERE, e.getMessage());
			} catch (ExecutionException e) {
				LOGGER.log(Level.SEVERE, e.getMessage());
			}
		}
		
		pull.shutdown();
		return result;
	}
	
	private static class SinCosEvaluator implements Callable<Double>{

		private double from;
		private double to;
		private double step;
		
		private double result = 0;
		
		public SinCosEvaluator(double from, double to, double step){
			this.from = from;
			this.to = to;
			this.step = step;
		}
		
		public Double call(){
			long precision = Math.round(1/step);
            System.out.println("[ " + from + " , " + to + " )");
            for(double i = from; i < to; i += step){
            		double value = Math.round(i*precision)/(double)precision;
                    result += func(value);
            }
            return result;
		}
		
		private double func(double arg){
			return Math.sin(arg)*Math.cos(arg);
		}
	}
	
	//test
	public static void main(String[] str){
		SinCos sinCos = new SinCos();
		System.out.println(sinCos.evaluate(5, 100, 0.01));
	}
}
